前端进阶之旅前端进阶之旅
基础篇
进阶篇
高频篇
精选篇
手写篇
面经篇
AI 篇
原理篇
每日一题
小程序题库
知识卡片
  • 场景篇按分类整理的大前端场景考点
  • 历年面经按年份追踪真实考点
  • 算法题库NEW在线编码即时判题
  • 专项自测100 题快速查漏
  • 前端基础
    • HTTP从报文一路讲到 HTTPS
    • 浏览器渲染、事件循环、进程
    • 计算机基础Linux、网络、操作系统
  • 进阶专项
    • 设计模式23 种模式怎么用
    • 前端系统进阶学习大型项目工程化
    • 前端综合文章长期沉淀的实践文
  • 工程与工具
    • Node学习指南从环境搭建到服务端
    • NPM工作流script、依赖与发布
    • Docker容器化部署上手
    • Canvas图形与动画实战
  • 路线与导图
    • 思维导图知识点全景图
    • 学习路线按图索骥不跑偏
  • 动态
    • 公众号动态公众号历史文章
    • 博客动态站长的技术博客
    • 开发者导航常用工具与文档站
  • AI 助手随时提问,即时解析
  • AI 模拟面试模拟真实面试 + 报告
  • AI 知识地图串起全站知识点
  • AI 定制路线按你的简历现排
AI 热点
旧版
基础篇
进阶篇
高频篇
精选篇
手写篇
面经篇
AI 篇
原理篇
每日一题
小程序题库
知识卡片
  • 场景篇按分类整理的大前端场景考点
  • 历年面经按年份追踪真实考点
  • 算法题库NEW在线编码即时判题
  • 专项自测100 题快速查漏
  • 前端基础
    • HTTP从报文一路讲到 HTTPS
    • 浏览器渲染、事件循环、进程
    • 计算机基础Linux、网络、操作系统
  • 进阶专项
    • 设计模式23 种模式怎么用
    • 前端系统进阶学习大型项目工程化
    • 前端综合文章长期沉淀的实践文
  • 工程与工具
    • Node学习指南从环境搭建到服务端
    • NPM工作流script、依赖与发布
    • Docker容器化部署上手
    • Canvas图形与动画实战
  • 路线与导图
    • 思维导图知识点全景图
    • 学习路线按图索骥不跑偏
  • 动态
    • 公众号动态公众号历史文章
    • 博客动态站长的技术博客
    • 开发者导航常用工具与文档站
  • AI 助手随时提问,即时解析
  • AI 模拟面试模拟真实面试 + 报告
  • AI 知识地图串起全站知识点
  • AI 定制路线按你的简历现排
AI 热点
旧版
  • 基础篇

    • 环境搭建
    • node部署
    • 基础应用
  • 内置模块

    • 1.0 本地路径处理 path
    • 2.0 文件系统操作 fs
    • 3.1 基础调试 console
    • 3.2 本地调试远程服务器上的Node代码
    • 4.1 网络服务 http
    • 4.2 网络服务 http res
    • 4.3 网络服务 http req
    • 4.4 网络服务 http server
    • 4.5 网络服务 http client
    • 4.6 网络服务 https
    • 4.7 网络TCP net
    • 4.8 网络UDP dgram
    • 4.9 域名解析 dns
    • 5.0 网络地址解析 url
    • 5.1 URL查询字符串 querystring
    • 6.1 流操作 stream
    • 6.2 逐行读取 readline
    • 7.1 进程相关 process
    • 7.2 子进程 child
    • 8.1 二进制数据 buffer
    • 8.2 二进制解码 string_decoder
    • 9.1 事件机制 events
    • 9.2 实用工具模块 util
    • 9.3 数据加密 crypto
    • 9.4 MD5入门介绍及crypto模块的应用
    • 9.4 资源压缩 zlib
    • 9.5 集群 cluster
    • 9.6 v8
  • 进阶篇

    • 5分钟入门非对称加密用法
    • cluster
    • cookie_parser深入
    • crypto模块之理论篇
    • express+cookie_parser签名机制深入剖析
    • express+session实现简易身份认证
    • https
    • log4js入门实例
    • node8_napi
    • 使用 async 控制并发
    • 使用 eventproxy 控制并发
    • 使用 superagent 与 cheerio 完成简单爬虫
    • 基于express+muter的文件上传
    • 将图片转成datauri嵌入到html
    • 常用中间件 body_parser 实现解析
    • 日志模块morgan
    • 服务端字符编解码&乱码处理 charset_enc_dec
    • 测试用例mocha,should,istanbul
    • 调试日志打印debug模块
  • Express

    • 1.1 Express概览篇
    • 1.2 Express
  • Koa2

    • 1.0 koa2概览篇
    • 1.1 快速开始
    • 1.2 async await使用
    • 1.3 koa2简析结构
    • 1.4 koa中间件开发与使用
    • 10.1 单元测试
    • 11.1 开发debug
    • 12.1 快速启动
    • 12.2 框架设计
    • 12.3 分层操作
    • 12.4 数据库设计
    • 12.5 路由设计
    • 12.6 webpack4环境搭建
    • 12.7 使用react
    • 12.8 登录注册功能实现
    • 12.9 session登录态判断处理
    • 13.1 import export使用
    • 2.1 原生koa2实现路由
    • 2.2 koa router中间
    • 3.1 GET请求数据获取
    • 3.2 POST请求数据获取
    • 3.3 koa bodyparser中间件
    • 4.1 原生koa2实现静态资源服务器
    • 4.2 koa static中间件
    • 5.1 koa2使用cookie
    • 5.2 koa2实现session
    • 6.1 koa2加载模板引擎
    • 6.2 ejs模板引擎
    • 7.1 busboy模块
    • 7.2 上传文件简单实现
    • 7.3 异步上传图片实现
    • 8.1 mysql模块
    • 8.2 async await封装使用mysql
    • 8.3 项目建表初始化
    • 9.1 原生koa2实现JSONP
    • 9.2 koa jsonp中间件
  • 其他

    • 操作数据库
    • Session 与 Token
    • Cookie、Session、Token、JWT
    • Socket

# 网络服务 http server

30 秒速记

  • http.createServer 只干两件事:管连接、把报文解析成 req / res;路由、body 解析、校验都是你自己的事(或者交给框架)
  • 超时分几层:headersTimeout(收请求头,默认 60s)、requestTimeout(收完整请求,v18 起默认 300s)、keepAliveTimeout(空闲长连接,默认 5s)、server.timeout(socket 不活动,v13 起默认 0 不限)
  • 要有明确策略的事件:error(监听失败)、clientError(报文坏了)、upgrade(WebSocket)、connect(代理隧道)
  • 多进程监听同一端口靠 cluster 或平台负载均衡,进程之间内存不共享,会话和缓存要放 Redis 这类外部存储

Node 的 http.Server 是很薄的一层:接连接、解析报文、把 req 和 res 交给你,剩下的路由、解析 body、超时、优雅关闭都得自己管。 Express、Koa 本质上就是在 request 回调里帮你把这些补上。面试里常被追问的是超时,它不是一个值,而是分阶段的好几个:收请求头、收完整请求、长连接空闲、socket 不活动,各防一种慢攻击或泄漏。线上还要留意 keepAliveTimeout 要比前面负载均衡的空闲超时长,不然会偶发 502。

理解「网络服务 http server」时,要先明确输入、运行阶段和可观察输出。这里的交互实验会分别执行正常路径与失败路径,并把 Node.js 的关键状态变化和同屏代码对应起来;不能只记命令名称。

工程中还要验证退出码、资源清理和异常输入。属于 network 场景的配置应保持最小可复现,并在开发环境与 CI 中使用相同命令复跑,避免把平台差异或隐式默认值带到线上。

一个能上线的最小服务,比 res.end('ok') 多不了几行,但这几行全是边界:

const http = require('http');

const server = http.createServer((req, res) => {
  res.end('ok');
});

server.headersTimeout = 60_000;    // 请求头必须在 60s 内收完,防慢速攻击
server.requestTimeout = 300_000;   // 整个请求最多收 300s
server.keepAliveTimeout = 65_000;  // 空闲长连接留 65s,要比前面负载均衡的空闲超时长

server.on('error', (err) => {      // 监听失败,比如端口被占
  console.error('listen failed:', err.code);
  process.exit(1);
});

server.listen(process.env.PORT || 3000, () => {
  console.log('listening on', server.address().port);
});

process.on('SIGTERM', () => {      // 优雅停机:不接新连接,等存量请求做完
  server.close(() => process.exit(0));
});
@前端进阶之旅: 代码已经复制到剪贴板

读这个模块可以按一条主线:连接进来(connection)、请求头解析完(request)、读 body、写响应、连接复用或关闭、服务停机(close)。每个阶段都有对应的超时和异常事件,面试被问到某个事件或配置时,先把它放回这条线上的位置,就知道它防的是什么。

面试官追问

追问 1Node 服务挂在负载均衡后面,偶发 502,服务日志里什么都没有,先看什么?
参考回答

先看 server.keepAliveTimeout,默认只有 5s。负载均衡的空闲超时如果是 60s,它会拿一条 Node 已经关掉的连接去发请求。把 keepAliveTimeout 调到比负载均衡长,比如 65s,老版本还要让 headersTimeout 再大一点。

追问 2有人慢悠悠地一个字节一个字节发请求头拖住连接,Node 靠哪个配置防?
参考回答

headersTimeout,规定请求头必须多久内发完,默认 60s;requestTimeout 再兜住整个请求。超时后 Node 直接回 408 并关连接。

追问 3cluster 起了 4 个进程监听 3000,用户登录状态存在内存里,为什么时有时无?
参考回答

每个进程各有一份内存,请求落到哪个进程不确定,登录写在进程一,下次请求落到进程二就没了。会话放 Redis 或者改用 JWT,别存进程内存。

追问 4http.createServer 和 Express 是什么关系?
参考回答

Express 的 app 本身就是一个 (req, res) => {} 函数,app.listen() 内部还是 http.createServer(app)。它没换掉 Node 的 HTTP 层,只是在 request 回调里加了路由和中间件。

# http服务端概览

30 秒速记

  • 一次请求在服务端走的路:TCP 建连(connection)→ 请求头解析完(request)→ 读 body(data / end)→ 写响应(res.end)→ 连接复用或关闭
  • 三个角色:http.Server 管全局和事件,req(IncomingMessage)只读,res(ServerResponse)只写
  • request 回调触发时只有请求头,body 还在路上,要自己读
  • 所有请求的回调都在一个主线程上跑,回调里的同步重活会卡住所有人
  • 出了问题按阶段找:连不上看监听,400 看 clientError,一直转圈看哪个分支漏了 res.end()

服务端处理一个请求就是一条流水线:建连、解析请求头、读请求体、写响应,最后决定连接是复用还是关掉。 Node 把它拆成几个对象:http.Server 负责接连接、发事件,req 是只读的请求流,res 是只写的响应流。新人最常误解的是 request 回调触发时请求体还没到,它只代表请求头解析完了。排查问题我也按这几个阶段去定位:连不上看监听和端口,报 400 看 clientError,一直转圈多半是哪个分支漏了 res.end()。

理解「http服务端概览」时,要先明确输入、运行阶段和可观察输出。这里的交互实验会分别执行正常路径与失败路径,并把 Node.js 的关键状态变化和同屏代码对应起来;不能只记命令名称。

工程中还要验证退出码、资源清理和异常输入。属于 network 场景的配置应保持最小可复现,并在开发环境与 CI 中使用相同命令复跑,避免把平台差异或隐式默认值带到线上。

面试官追问

追问 1接口偶发一直转圈不返回,代码里也没报错,最可能是什么?
参考回答

某个分支没调 res.end(),比如提前 return 了,或者异步回调里的异常被吞了。Node 不会替你结束响应,最后只能等客户端或网关超时。每个分支都要有出口,或者交给框架的统一错误处理。

追问 2res.end() 之后再调 res.setHeader() 会怎样?
参考回答

抛 ERR_HTTP_HEADERS_SENT,响应头已经跟着第一块数据发出去了。设置头要在 res.write() / res.end() 之前,Express 里那个 Cannot set headers after they are sent 报错就是这么来的。

追问 3为什么 request 回调里直接拿不到 POST 的数据?
参考回答

回调触发时 Node 只解析完了请求头,body 还在一块块地来。要监听 data 攒起来、在 end 里用,或者 for await (const chunk of req)。

追问 4一个请求进来,Node 是开一个线程去处理吗?
参考回答

不是,所有请求的回调都在同一个主线程上跑,靠事件循环轮流处理。所以回调里一个同步的大循环会把所有请求一起卡住,CPU 重活要丢给 worker_threads 或者拆成单独的服务。

# 创建server

30 秒速记

  • 一行就能起:http.createServer((req, res) => res.end('ok')).listen(3000)
  • http.createServer(fn) 和 new http.Server(fn) 等价,fn 被挂成 request 事件的监听器
  • listen 是异步的:成功走回调 / listening 事件,失败走 error 事件,不会在那一行抛出来
  • 每个请求都要有出口,res.end() 不调,客户端就一直挂着
  • 端口别写死:process.env.PORT || 3000;容器里要能被外部访问,别绑 127.0.0.1

创建服务就是 http.createServer(requestListener) 再 listen(端口),requestListener 会在每个请求到来时被调用,拿到 req 和 res。 createServer 和 new http.Server 是一回事,传进去的函数本质上就是 request 事件的监听器,写成 server.on('request', fn) 效果一样。要注意 listen 是异步的,端口被占不会在这一行抛出来,而是走 error 事件,所以我一般顺手挂上 error 监听,在 listen 的回调里再打「启动成功」。

几行代码搞定

var
基础篇
进阶篇
高频篇
精选篇
手写篇
面经篇
AI 篇
原理篇
每日一题
小程序题库
知识卡片
  • 场景篇按分类整理的大前端场景考点
  • 历年面经按年份追踪真实考点
  • 算法题库NEW在线编码即时判题
  • 专项自测100 题快速查漏
  • 前端基础
    • HTTP从报文一路讲到 HTTPS
    • 浏览器渲染、事件循环、进程
    • 计算机基础Linux、网络、操作系统
  • 进阶专项
    • 设计模式23 种模式怎么用
    • 前端系统进阶学习大型项目工程化
    • 前端综合文章长期沉淀的实践文
  • 工程与工具
    • Node学习指南从环境搭建到服务端
    • NPM工作流script、依赖与发布
    • Docker容器化部署上手
    • Canvas图形与动画实战
  • 路线与导图
    • 思维导图知识点全景图
    • 学习路线按图索骥不跑偏
  • 动态
    • 公众号动态公众号历史文章
    • 博客动态站长的技术博客
    • 开发者导航常用工具与文档站
  • AI 助手随时提问,即时解析
  • AI 模拟面试模拟真实面试 + 报告
  • AI 知识地图串起全站知识点
  • AI 定制路线按你的简历现排
AI 热点
旧版
  • 基础篇

    • 环境搭建
    • node部署
    • 基础应用
  • 内置模块

    • 1.0 本地路径处理 path
    • 2.0 文件系统操作 fs
    • 3.1 基础调试 console
    • 3.2 本地调试远程服务器上的Node代码
    • 4.1 网络服务 http
    • 4.2 网络服务 http res
    • 4.3 网络服务 http req
    • 4.4 网络服务 http server
      • http服务端概览
      • 创建server
      • 获取请求方信息
        • HTTP版本、HTTP method、headers、url
        • 获取get请求参数
        • 获取post请求参数
      • 枯燥的事件
      • 不常用接口
      • 不常用属性
    • 4.5 网络服务 http client
    • 4.6 网络服务 https
    • 4.7 网络TCP net
    • 4.8 网络UDP dgram
    • 4.9 域名解析 dns
    • 5.0 网络地址解析 url
    • 5.1 URL查询字符串 querystring
    • 6.1 流操作 stream
    • 6.2 逐行读取 readline
    • 7.1 进程相关 process
    • 7.2 子进程 child
    • 8.1 二进制数据 buffer
    • 8.2 二进制解码 string_decoder
    • 9.1 事件机制 events
    • 9.2 实用工具模块 util
    • 9.3 数据加密 crypto
    • 9.4 MD5入门介绍及crypto模块的应用
    • 9.4 资源压缩 zlib
    • 9.5 集群 cluster
    • 9.6 v8
  • 进阶篇

    • 5分钟入门非对称加密用法
    • cluster
    • cookie_parser深入
    • crypto模块之理论篇
    • express+cookie_parser签名机制深入剖析
    • express+session实现简易身份认证
    • https
    • log4js入门实例
    • node8_napi
    • 使用 async 控制并发
    • 使用 eventproxy 控制并发
    • 使用 superagent 与 cheerio 完成简单爬虫
    • 基于express+muter的文件上传
    • 将图片转成datauri嵌入到html
    • 常用中间件 body_parser 实现解析
    • 日志模块morgan
    • 服务端字符编解码&乱码处理 charset_enc_dec
    • 测试用例mocha,should,istanbul
    • 调试日志打印debug模块
  • Express

    • 1.1 Express概览篇
    • 1.2 Express
  • Koa2

    • 1.0 koa2概览篇
    • 1.1 快速开始
    • 1.2 async await使用
    • 1.3 koa2简析结构
    • 1.4 koa中间件开发与使用
    • 10.1 单元测试
    • 11.1 开发debug
    • 12.1 快速启动
    • 12.2 框架设计
    • 12.3 分层操作
    • 12.4 数据库设计
    • 12.5 路由设计
    • 12.6 webpack4环境搭建
    • 12.7 使用react
    • 12.8 登录注册功能实现
    • 12.9 session登录态判断处理
    • 13.1 import export使用
    • 2.1 原生koa2实现路由
    • 2.2 koa router中间
    • 3.1 GET请求数据获取
    • 3.2 POST请求数据获取
    • 3.3 koa bodyparser中间件
    • 4.1 原生koa2实现静态资源服务器
    • 4.2 koa static中间件
    • 5.1 koa2使用cookie
    • 5.2 koa2实现session
    • 6.1 koa2加载模板引擎
    • 6.2 ejs模板引擎
    • 7.1 busboy模块
    • 7.2 上传文件简单实现
    • 7.3 异步上传图片实现
    • 8.1 mysql模块
    • 8.2 async await封装使用mysql
    • 8.3 项目建表初始化
    • 9.1 原生koa2实现JSONP
    • 9.2 koa jsonp中间件
  • 其他

    • 操作数据库
    • Session 与 Token
    • Cookie、Session、Token、JWT
    • Socket
完整面试题地址:
作者:程序员poetry
扫码关注作者公众号:「前端进阶之旅」 每天分享技术干货
前端进阶之旅公众号二维码

网络服务 http server|Nodejs专题系列

# 网络服务 http server

30 秒速记

  • http.createServer 只干两件事:管连接、把报文解析成 req / res;路由、body 解析、校验都是你自己的事(或者交给框架)
  • 超时分几层:headersTimeout(收请求头,默认 60s)、requestTimeout(收完整请求,v18 起默认 300s)、keepAliveTimeout(空闲长连接,默认 5s)、server.timeout(socket 不活动,v13 起默认 0 不限)
  • 要有明确策略的事件:error(监听失败)、clientError(报文坏了)、upgrade(WebSocket)、connect(代理隧道)
  • 多进程监听同一端口靠 cluster 或平台负载均衡,进程之间内存不共享,会话和缓存要放 Redis 这类外部存储

Node 的 http.Server 是很薄的一层:接连接、解析报文、把 req 和 res 交给你,剩下的路由、解析 body、超时、优雅关闭都得自己管。 Express、Koa 本质上就是在 request 回调里帮你把这些补上。面试里常被追问的是超时,它不是一个值,而是分阶段的好几个:收请求头、收完整请求、长连接空闲、socket 不活动,各防一种慢攻击或泄漏。线上还要留意 keepAliveTimeout 要比前面负载均衡的空闲超时长,不然会偶发 502。

理解「网络服务 http server」时,要先明确输入、运行阶段和可观察输出。这里的交互实验会分别执行正常路径与失败路径,并把 Node.js 的关键状态变化和同屏代码对应起来;不能只记命令名称。

工程中还要验证退出码、资源清理和异常输入。属于 network 场景的配置应保持最小可复现,并在开发环境与 CI 中使用相同命令复跑,避免把平台差异或隐式默认值带到线上。

一个能上线的最小服务,比 res.end('ok') 多不了几行,但这几行全是边界:

const http = require('http');

const server = http.createServer((req, res) => {
  res.end('ok');
});

server.headersTimeout = 60_000;    // 请求头必须在 60s 内收完,防慢速攻击
server.requestTimeout = 300_000;   // 整个请求最多收 300s
server.keepAliveTimeout = 65_000;  // 空闲长连接留 65s,要比前面负载均衡的空闲超时长

server.on('error', (err) => {      // 监听失败,比如端口被占
  console.error('listen failed:', err.code);
  process.exit(1);
});

server.listen(process.env.PORT || 3000, () => {
  console.log('listening on', server.address().port);
});

process.on('SIGTERM', () => {      // 优雅停机:不接新连接,等存量请求做完
  server.close(() => process.exit(0));
});
@前端进阶之旅: 代码已经复制到剪贴板

读这个模块可以按一条主线:连接进来(connection)、请求头解析完(request)、读 body、写响应、连接复用或关闭、服务停机(close)。每个阶段都有对应的超时和异常事件,面试被问到某个事件或配置时,先把它放回这条线上的位置,就知道它防的是什么。

面试官追问

追问 1Node 服务挂在负载均衡后面,偶发 502,服务日志里什么都没有,先看什么?
参考回答

先看 server.keepAliveTimeout,默认只有 5s。负载均衡的空闲超时如果是 60s,它会拿一条 Node 已经关掉的连接去发请求。把 keepAliveTimeout 调到比负载均衡长,比如 65s,老版本还要让 headersTimeout 再大一点。

追问 2有人慢悠悠地一个字节一个字节发请求头拖住连接,Node 靠哪个配置防?
参考回答

headersTimeout,规定请求头必须多久内发完,默认 60s;requestTimeout 再兜住整个请求。超时后 Node 直接回 408 并关连接。

追问 3cluster 起了 4 个进程监听 3000,用户登录状态存在内存里,为什么时有时无?
参考回答

每个进程各有一份内存,请求落到哪个进程不确定,登录写在进程一,下次请求落到进程二就没了。会话放 Redis 或者改用 JWT,别存进程内存。

追问 4http.createServer 和 Express 是什么关系?
参考回答

Express 的 app 本身就是一个 (req, res) => {} 函数,app.listen() 内部还是 http.createServer(app)。它没换掉 Node 的 HTTP 层,只是在 request 回调里加了路由和中间件。

# http服务端概览

30 秒速记

  • 一次请求在服务端走的路:TCP 建连(connection)→ 请求头解析完(request)→ 读 body(data / end)→ 写响应(res.end)→ 连接复用或关闭
  • 三个角色:http.Server 管全局和事件,req(IncomingMessage)只读,res(ServerResponse)只写
  • request 回调触发时只有请求头,body 还在路上,要自己读
  • 所有请求的回调都在一个主线程上跑,回调里的同步重活会卡住所有人
  • 出了问题按阶段找:连不上看监听,400 看 clientError,一直转圈看哪个分支漏了 res.end()

服务端处理一个请求就是一条流水线:建连、解析请求头、读请求体、写响应,最后决定连接是复用还是关掉。 Node 把它拆成几个对象:http.Server 负责接连接、发事件,req 是只读的请求流,res 是只写的响应流。新人最常误解的是 request 回调触发时请求体还没到,它只代表请求头解析完了。排查问题我也按这几个阶段去定位:连不上看监听和端口,报 400 看 clientError,一直转圈多半是哪个分支漏了 res.end()。

理解「http服务端概览」时,要先明确输入、运行阶段和可观察输出。这里的交互实验会分别执行正常路径与失败路径,并把 Node.js 的关键状态变化和同屏代码对应起来;不能只记命令名称。

工程中还要验证退出码、资源清理和异常输入。属于 network 场景的配置应保持最小可复现,并在开发环境与 CI 中使用相同命令复跑,避免把平台差异或隐式默认值带到线上。

面试官追问

追问 1接口偶发一直转圈不返回,代码里也没报错,最可能是什么?
参考回答

某个分支没调 res.end(),比如提前 return 了,或者异步回调里的异常被吞了。Node 不会替你结束响应,最后只能等客户端或网关超时。每个分支都要有出口,或者交给框架的统一错误处理。

追问 2res.end() 之后再调 res.setHeader() 会怎样?
参考回答

抛 ERR_HTTP_HEADERS_SENT,响应头已经跟着第一块数据发出去了。设置头要在 res.write() / res.end() 之前,Express 里那个 Cannot set headers after they are sent 报错就是这么来的。

追问 3为什么 request 回调里直接拿不到 POST 的数据?
参考回答

回调触发时 Node 只解析完了请求头,body 还在一块块地来。要监听 data 攒起来、在 end 里用,或者 for await (const chunk of req)。

追问 4一个请求进来,Node 是开一个线程去处理吗?
参考回答

不是,所有请求的回调都在同一个主线程上跑,靠事件循环轮流处理。所以回调里一个同步的大循环会把所有请求一起卡住,CPU 重活要丢给 worker_threads 或者拆成单独的服务。

# 创建server

30 秒速记

  • 一行就能起:http.createServer((req, res) => res.end('ok')).listen(3000)
  • http.createServer(fn) 和 new http.Server(fn) 等价,fn 被挂成 request 事件的监听器
  • listen 是异步的:成功走回调 / listening 事件,失败走 error 事件,不会在那一行抛出来
  • 每个请求都要有出口,res.end() 不调,客户端就一直挂着
  • 端口别写死:process.env.PORT || 3000;容器里要能被外部访问,别绑 127.0.0.1

创建服务就是 http.createServer(requestListener) 再 listen(端口),requestListener 会在每个请求到来时被调用,拿到 req 和 res。 createServer 和 new http.Server 是一回事,传进去的函数本质上就是 request 事件的监听器,写成 server.on('request', fn) 效果一样。要注意 listen 是异步的,端口被占不会在这一行抛出来,而是走 error 事件,所以我一般顺手挂上 error 监听,在 listen 的回调里再打「启动成功」。

几行代码搞定

var http = require('http');
var requestListener = function(req, res){
    res.end('ok');
};
var server = http.createServer(requestListener);
// var server = new http.Server(requestListener); 跟上面是等价的
server.listen(3000);
@前端进阶之旅: 代码已经复制到剪贴板

面试官追问

追问 1createServer 传了回调,又写了 server.on('request', fn2),请求来了会怎样?
参考回答

两个都会执行,createServer 的回调就是第一个 request 监听器。如果两边都 res.end('...'),第二次的内容发不出去,新版本还会报 ERR_STREAM_WRITE_AFTER_END。

追问 2server.listen(3000) 下一行紧跟着打「启动成功」,有什么问题?
参考回答

listen 是异步的,这句打出来时还没真正绑上端口;端口被占的话,日志说成功、紧接着进程报 EADDRINUSE。成功日志放进 listen 的回调里,失败挂 server.on('error')。

追问 3访问接口一直转圈,服务端代码就几行,先查什么?
参考回答

先看回调的每个分支是不是都调了 res.end(),Node 不会自动结束响应。再确认访问的端口和 listen 的是同一个,curl -v 看连接有没有建立。

追问 4服务在容器里起来了,从外面访问不到,可能是什么原因?
参考回答

listen 绑到了 127.0.0.1 或 localhost,只接受容器内部的连接。不传 host 时 Node 默认监听所有地址;显式写了的话改成 0.0.0.0,再检查容器的端口映射。

# 获取请求方信息

← 4.3 网络服务 http req4.5 网络服务 http client →

fe